package cn.fl.settlement.service.impl;

import cmm.comm.facade.framework.api.ISysDictionaryApiService;
import cmm.comm.facade.framework.dto.SysDictionaryDTO;
import cmm.mid.core.framework.page.ListPageVO;
import cn.cmm.base.framework.constant.BaseConstant;
import cn.cmm.base.framework.constant.BaseExceptionConstant;
import cn.cmm.base.framework.exception.BaseException;
import cn.cmm.base.framework.logger.eum.LogExceptionEnum;
import cn.cmm.base.framework.utils.BaseLogUtils;
import cn.cmm.base.framework.utils.CollectionUtils;
import cn.cmm.base.framework.utils.DecimalUtils;
import cn.cmm.base.framework.utils.StringUtils;
import cn.fl.capital.api.ICapCstSettleApiService;
import cn.fl.capital.condition.CapCstStmApplyQC;
import cn.fl.capital.constant.CapitalConstant;
import cn.fl.capital.constant.SettleConstant;
import cn.fl.capital.dto.CapCstStmApplyDTO;
import cn.fl.capital.dto.CapOverdueInfoDTO;
import cn.fl.framework.base.context.CurrentThreadContext;
import cn.fl.framework.constant.DictionaryConstant;
import cn.fl.project.condition.PrjPrdDtlQueryCondition;
import cn.fl.project.condition.PrjPrdPaySchMQueryCondition;
import cn.fl.project.constant.PrjPrdPaySchMConstant;
import cn.fl.project.constant.PrjQuatPrpsConstant;
import cn.fl.project.dto.PrjBscInfoDTO;
import cn.fl.project.dto.PrjPrdDtlDTO;
import cn.fl.project.dto.PrjPrdPaySchDDTO;
import cn.fl.project.dto.PrjPrdPaySchMDTO;
import cn.fl.project.service.IPrjPrdPaySchMApiService;
import cn.fl.project.service.IProjectApiService;
import cn.fl.project.transform.PrjPrdDtlVOTransform;
import cn.fl.settle.api.ISettleBillApiService;
import cn.fl.settle.condition.PaySchMSettleQueryCondition;
import cn.fl.settle.dto.PaySchMSettleDTO;
import cn.fl.settlement.service.ISettleBillService;
import cn.fl.settlement.service.ISettlementFileService;
import cn.fl.settlement.vo.PaySchDSettlePageVO;
import cn.fl.settlement.vo.PaySchMSettlePageVO;
import cn.lionbridgecapital.loan.model.exception.BusinessException;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class SettleBillServiceImpl implements ISettleBillService {


    @Autowired
    private ISettleBillApiService settleBillApiService;

    @Autowired
    private IProjectApiService projectApiService;

    @Autowired
    private IPrjPrdPaySchMApiService prjPrdPaySchMApiService;

    @Autowired
    private ISysDictionaryApiService sysDictionaryApiService;

    @Autowired
    private ICapCstSettleApiService capCstSettleApiService;

    @Autowired
    private ISettlementFileService settlementFileService;

    @Override
    public void getSettlePdIfCheckPass(Long paySchId, ModelAndView view) throws BaseException {
        try {
            if (null == paySchId) {
                throw new BaseException(BaseExceptionConstant.BASE_EXCEPTION_CODE_600, "支付表ID不能为空!");
            }
            PrjPrdPaySchMDTO enabledPaySchM = settleBillApiService.getSettlePdIfCheckPass(paySchId);
            // 查找项目基础信息
            PrjBscInfoDTO prjBscInfoDTO = projectApiService.selectById(enabledPaySchM.getPrjId());

            if (PrjPrdPaySchMConstant.PAY_SCH_TYP_CD_ZF.equals(enabledPaySchM.getPaySchTypCd())) {
                // 查询项目下的所有支付表
                PrjPrdPaySchMQueryCondition condition = new PrjPrdPaySchMQueryCondition();
                condition.setPrjId(enabledPaySchM.getPrjId());
                condition.setIsAllBiz(BaseConstant.IS_YESNO_YES);
                List<PrjPrdPaySchMDTO> allPaySchList = prjPrdPaySchMApiService.searchPrjPrdPaySchMList(condition);
                List<PrjPrdPaySchMDTO> wsPaySchList = Lists.newArrayListWithCapacity(allPaySchList.size() - 1);
                // 循环找出我司支付表
                for (PrjPrdPaySchMDTO paySchMDTO : allPaySchList) {
                    if (PrjPrdPaySchMConstant.PAY_SCH_TYP_CD_WS.equals(paySchMDTO.getPaySchTypCd())) {
                        wsPaySchList.add(paySchMDTO);
                    }
                }
                view.addObject("wsPaySchList", wsPaySchList);
            }
            view.addObject("prj", prjBscInfoDTO);
            view.addObject("enabledPaySchM", enabledPaySchM);
        } catch (Exception e) {
            throw e;
        }
    }

    @Override
    public void getSettleDataPreview(Long paySchId, Integer settlePd, ModelAndView view) throws BaseException {
        PaySchMSettleQueryCondition condition = new PaySchMSettleQueryCondition();
        condition.setPaySchId(paySchId);
        condition.setSettlePd(settlePd);

        PaySchMSettleDTO settleData = settleBillApiService.getSettleData(condition);
        if (settleData == null) {
            throw new BusinessException("计算结清数据失败！");
        }
        if (StringUtils.isEmpty(settleData.getSettleType())) {
            throw new BaseException("结清类型不能为空！");
        }
        // 应还项列表数据、结清费用项列表数据
        List<PaySchDSettlePageVO> shouldPayList = Lists.newArrayList();
        if (settleData.getSettleItemList() != null) {
            Map<String, String> stlFeeTypCdMap = sysDictionaryApiService.searchGroupToMap(CurrentThreadContext.getCurrentSysCd(),
                    CurrentThreadContext.getCurrentOrgCd(),
                    DictionaryConstant.CODE_PRJ_QUAT_FEE_SETT_TYP_CD);

            for (PaySchMSettleDTO.SettleItem item : settleData.getSettleItemList()) {
                PaySchDSettlePageVO settleItem = new PaySchDSettlePageVO();
                Long amt = item.getAmt();
                if (Integer.parseInt(PrjQuatPrpsConstant.CODE_PRJ_QUAT_CASH_FLOW_OUT) == item.getCapFlow()) {
                    amt = -1 * amt;
                }
                settleItem.setFeeAmt(DecimalUtils.convertFenToYuan(amt));
                settleItem.setArAmt(settleItem.getFeeAmt());
                settleItem.setFeeTypCd(item.getCd());
                if (CapitalConstant.CODE_FEE_TYP_CD_S02.equals(item.getCd())) {
                    settleItem.setFeeTypCdNm("未还利息合计");
                } else if (CapitalConstant.CODE_FEE_TYP_CD_S03.equals(item.getCd())) {
                    settleItem.setFeeTypCdNm("未还本金合计");
                } else if (CapitalConstant.CODE_FEE_TYP_CD_S05.equals(item.getCd())) {
                    settleItem.setFeeTypCdNm("逾期罚息合计");
                } else if (DictionaryConstant.CODE_PRJ_QUAT_FEE_SETT_TYP_CD.equals(item.getFeeClsCd())) {
                    settleItem.setFeeTypCdNm(stlFeeTypCdMap.get(item.getCd()));
                } else if (StringUtils.isNotEmpty(item.getFeeClsCd())
                        && StringUtils.isNotEmpty(settleItem.getFeeTypCd())) {
                    SysDictionaryDTO dictionaryDTO = sysDictionaryApiService.getCode(CapitalConstant.SYSCD,
                            CapitalConstant.SYSORG,
                            settleItem.getFeeClsCd(),
                            settleItem.getFeeTypCd());
                    if (dictionaryDTO != null) {
                        settleItem.setFeeTypCdNm(dictionaryDTO.getCodeNm());
                    }
                }
                settleItem.setCapFlow(item.getCapFlow().toString());
                settleItem.setFeeClsCd(item.getFeeClsCd());

                shouldPayList.add(settleItem);
            }
        }
        ListPageVO<PaySchDSettlePageVO> shouldPayListPage = new ListPageVO<>(shouldPayList, shouldPayList.size());
        view.addObject("shouldPayListPage", JSON.toJSONString(shouldPayListPage));

        commProcessData(settleData, view);
    }

    @Override
    public PaySchMSettleDTO getSettleDataFlow(String procId, ModelAndView view) throws BaseException {
        PaySchMSettleDTO settleData = settleBillApiService.getSettleDataForFlow(procId);

        commProcessData(settleData, view);
        return settleData;
    }

    @Override
    public Double refreshSettleAmt(Long paySchId) {
        PrjPrdPaySchMDTO paySchMDTO = prjPrdPaySchMApiService.selectPrjPrdPaySchMById(paySchId);
        if (paySchMDTO != null) {
            return DecimalUtils.convertFenToYuan(paySchMDTO.getStlAmt());
        } else {
            return null;
        }
    }

    @Override
    public void startFlow(Long paySchId, Integer settlePd) {
        try {
            boolean bol = settlementFileService.isUploadStlApplication(String.valueOf(paySchId));
            if (!bol) {
                throw new BaseException("请上传结清申请书！");
            }
            CapCstStmApplyDTO apply = new CapCstStmApplyDTO();
            apply.setPaySchId(paySchId);
            apply.setCurrentPd(settlePd);
            apply.setStlPd(settlePd);
            apply.setCrtTm(new Date());
            apply.setCrtUsrId(CurrentThreadContext.getCurrentUserId());
            apply.setCrtUsrName(CurrentThreadContext.getCurrentUserName());

            settleBillApiService.executeStartFlow(apply);
        } catch (BaseException e) {
            BaseLogUtils.newLogger("支付表{}发起结清流程业务异常：", paySchId).setThrowable(e).error(LogExceptionEnum.COMMON_CODE_0002);
            throw e;
        } catch (Exception e) {
            BaseLogUtils.newLogger("支付表{}发起结清流程系统异常：", paySchId).setThrowable(e).error(LogExceptionEnum.COMMON_CODE_0002);
            throw e;
        }
    }

    @Override
    public String querySettleStartResult(Long paySchId) {
        CapCstStmApplyQC capCstStmApplyQC = new CapCstStmApplyQC();
        capCstStmApplyQC.setPaySchId(paySchId);
        capCstStmApplyQC.setIsDel(BaseConstant.IS_YESNO_NO);
        capCstStmApplyQC.setSortName("CRT_TM");
        capCstStmApplyQC.setSortOrder(" DESC ");

        List<CapCstStmApplyDTO> applyDTOList = capCstSettleApiService.searchList(capCstStmApplyQC);
        if (CollectionUtils.isEmpty(applyDTOList)) {
            return null;
        }
        if (!SettleConstant.CODE_SETT_CLOSE.equals(applyDTOList.get(0).getStsCd())) {
            // 结清申请的状态非订单关闭，则认为发起成功
            return applyDTOList.get(0).getProcNo();
        }
        return null;
    }

    /**
     * 加工预览页面和附加页面需要的数据
     * @param settleData
     * @param view
     * @throws BaseException
     */
    private void commProcessData(PaySchMSettleDTO settleData, ModelAndView view) throws BaseException {
        PrjBscInfoDTO prjBscInfo = projectApiService.selectById(settleData.getPrjId());
        if (prjBscInfo == null) {
            throw new BaseException("未查询到项目基础信息！");
        }

        PaySchMSettlePageVO pageVO = new PaySchMSettlePageVO();
        pageVO.setPaySchId(settleData.getPaySchId());
        pageVO.setPaySchNo(settleData.getPaySchNo());
        pageVO.setWsPaySchId(settleData.getWsPaySchId());
        pageVO.setPrjId(prjBscInfo.getId());
        pageVO.setLsCntNo(prjBscInfo.getLsCntNo());
        pageVO.setCstId(prjBscInfo.getCstId());
        pageVO.setCstNm(prjBscInfo.getCstNm());
        pageVO.setSettleType(settleData.getSettleType());
        pageVO.setSettleTypeNm(SettleConstant.CODE_SETT_TYPE_NORMAL.equals(settleData.getSettleType()) ? "正常结清" : SettleConstant.CODE_SETT_TYPE_ADVANCE.equals(settleData.getSettleType()) ? "提前结清" : "");
        pageVO.setSettlePd(settleData.getSettlePd());
        pageVO.setTotalSettleAmt(DecimalUtils.convertFenToYuan(settleData.getTotalSettleAmt()));

        // 自结清期应还租金合计
        Long surplusRentTotalStl = 0l;
        // 结清前应还的每期租金合计
        Long rentBeforeSettleTotal = 0l;
        if (settleData.getRentList() != null) {
            for (PrjPrdPaySchDDTO paySchRent : settleData.getRentList()) {
                if (settleData.getSettlePd().intValue() > 0
                        && paySchRent.getPayPd().intValue() >= settleData.getSettlePd().intValue()) {
                    //剩余租金合计
                    surplusRentTotalStl += paySchRent.getFeeAmt().longValue();
                } else {
                    //结清开始时间前每期应还租金合计
                    rentBeforeSettleTotal += paySchRent.getFeeAmt().longValue();
                }
            }
        }

        // 应收本金合计
        Long totalPrinAmt = 0l;
        // 已收本金合计
        Long totalActPrinAmt = 0l;
        Long totalPrinArAmt = 0l;
        if (settleData.getPrincipalList() != null) {
            // S03本金表
            for (PrjPrdPaySchDDTO paySchPrincipal : settleData.getPrincipalList()) {
                totalPrinAmt += ifNull(paySchPrincipal.getFeeAmt().longValue());
                totalActPrinAmt += ifNull(paySchPrincipal.getPaidUpAmt());
                totalPrinArAmt += ifNull(paySchPrincipal.getArAmt());
            }
        }

        // 应收利息合计
        Long totalIntAmt = 0l;
        // 已收利息合计
        Long totalActIntAmt = 0l;
        Long totalIntArAmt = 0l;
        if (settleData.getInterestList() != null) {
            // S02利息表
            for (PrjPrdPaySchDDTO paySchInterest : settleData.getInterestList()) {
                totalIntAmt += ifNull(paySchInterest.getFeeAmt().longValue());
                totalActIntAmt += ifNull(paySchInterest.getPaidUpAmt());
                totalIntArAmt += ifNull(paySchInterest.getArAmt());
            }
        }

        // fee表
        List<PaySchDSettlePageVO> feeDetailList = Lists.newArrayList();
        // 计入首期款应收总额
        Long firstPayFeeAmt = 0l;
        // 计入首期款已收总额
        Long firstPayPaidUpAmt = 0l;
        if (settleData.getFeeList() != null) {
            // PRJ0026 所有费用类型
            Map<String, String> feeTypCdMap = this.sysDictionaryApiService.searchGroupToMap(CurrentThreadContext.getCurrentSysCd(),
                    CurrentThreadContext.getCurrentOrgCd(),
                    DictionaryConstant.CODE_PRJ_QUAT_FEE_ALL_TYP_CD);
            for (PrjPrdPaySchDDTO paySchFee : settleData.getFeeList()) {
                // 翻译费用中文名称
                if (feeTypCdMap.containsKey(paySchFee.getFeeTypCd())) {
                    paySchFee.setFeeTypCdNm(feeTypCdMap.get(paySchFee.getFeeTypCd()));
                }
                // PRJ0039
                if (PrjQuatPrpsConstant.CODE_PRJ_QUAT_FEE_CLS_TYP_PRPS.equals(paySchFee.getFeeClsCd())) {
                    PaySchDSettlePageVO paySchDSettleVO = new PaySchDSettlePageVO();
                    paySchDSettleVO.setId(paySchFee.getId());
                    paySchDSettleVO.setPaySchId(paySchFee.getPaySchId());
                    paySchDSettleVO.setFeeAmt(DecimalUtils.convertFenToYuan(paySchFee.getFeeAmt().longValue()));
                    paySchDSettleVO.setArAmt(DecimalUtils.convertFenToYuan(paySchFee.getArAmt()));
                    paySchDSettleVO.setPaidUpAmt(DecimalUtils.convertFenToYuan(paySchFee.getPaidUpAmt()));
                    paySchDSettleVO.setFeeTypCd(paySchFee.getFeeTypCd());
                    paySchDSettleVO.setFeeTypCdNm(paySchFee.getFeeTypCdNm());

                    feeDetailList.add(paySchDSettleVO);
                }
                // 计入首期款
                if (PrjQuatPrpsConstant.CODE_PRJ_QUAT_CNT_WAY_DOWNPAY.equals(paySchFee.getCntWayCd())) {
                    firstPayFeeAmt += paySchFee.getFeeAmt().longValue();
                    firstPayPaidUpAmt += paySchFee.getPaidUpAmt();
                }
            }
        }
        PaySchDSettlePageVO firstPayTotal = new PaySchDSettlePageVO();
        firstPayTotal.setFeeTypCdNm("首期款合计");
        firstPayTotal.setFeeAmt(DecimalUtils.convertFenToYuan(firstPayFeeAmt));
        firstPayTotal.setPaidUpAmt(DecimalUtils.convertFenToYuan(firstPayPaidUpAmt));
        feeDetailList.add(firstPayTotal);

        ListPageVO<PaySchDSettlePageVO> feeListPage = new ListPageVO<>(feeDetailList, feeDetailList.size());
        view.addObject("feeListPage", JSON.toJSONString(feeListPage));

        // 应收罚息合计
        Long penaltyAmt = 0l;
        // 已收罚息合计
        Long payAmount = 0l;
        if (settleData.getCapOverdueInfoDTO() != null) {
            CapOverdueInfoDTO capOverdueInfo = settleData.getCapOverdueInfoDTO();
            penaltyAmt = capOverdueInfo.getPenaltyAmount() == null ? 0 : capOverdueInfo.getPenaltyAmount();
            payAmount = capOverdueInfo.getTotalAmount() == null ? 0 : capOverdueInfo.getTotalAmount();
        }

        // 本利罚
        List<PaySchDSettlePageVO> blfList = Lists.newArrayList();
        PaySchDSettlePageVO principalTotal = new PaySchDSettlePageVO();
        principalTotal.setFeeTypCd(CapitalConstant.CODE_FEE_TYP_CD_S03);
        principalTotal.setFeeTypCdNm("本金");
        principalTotal.setFeeAmt(DecimalUtils.convertFenToYuan(totalPrinAmt));
        principalTotal.setPaidUpAmt(DecimalUtils.convertFenToYuan(totalActPrinAmt));
        principalTotal.setArAmt(DecimalUtils.convertFenToYuan(totalPrinArAmt));
        blfList.add(principalTotal);

        PaySchDSettlePageVO interestTotal = new PaySchDSettlePageVO();
        interestTotal.setFeeTypCd(CapitalConstant.CODE_FEE_TYP_CD_S02);
        interestTotal.setFeeTypCdNm("利息");
        interestTotal.setFeeAmt(DecimalUtils.convertFenToYuan(totalIntAmt));
        interestTotal.setPaidUpAmt(DecimalUtils.convertFenToYuan(totalActIntAmt));
        interestTotal.setArAmt(DecimalUtils.convertFenToYuan(totalIntArAmt));
        blfList.add(interestTotal);

        PaySchDSettlePageVO penaltyTotal = new PaySchDSettlePageVO();
        penaltyTotal.setFeeTypCd(CapitalConstant.CODE_FEE_TYP_CD_S05);
        penaltyTotal.setFeeTypCdNm("罚息");
        penaltyTotal.setFeeAmt(DecimalUtils.convertFenToYuan(penaltyAmt));
        penaltyTotal.setPaidUpAmt(DecimalUtils.convertFenToYuan(payAmount));
        blfList.add(penaltyTotal);
        ListPageVO<PaySchDSettlePageVO> blfListPage = new ListPageVO<>(blfList, blfList.size());
        view.addObject("blfListPage", JSON.toJSONString(blfListPage));

        // 核算金额校验位
        Long checkbitAmt = totalPrinAmt - totalActPrinAmt - totalPrinArAmt + totalIntAmt - totalActIntAmt - totalIntArAmt;
        pageVO.setCheckbitAmt(DecimalUtils.convertFenToYuan(checkbitAmt));
        pageVO.setSurplusRentTotalStl(DecimalUtils.convertFenToYuan(surplusRentTotalStl));
        pageVO.setRentBeforeSettleTotal(DecimalUtils.convertFenToYuan(rentBeforeSettleTotal));

        // 查询项目产品明细
        PrjPrdDtlQueryCondition prjPrdDtlQc = new PrjPrdDtlQueryCondition();
        prjPrdDtlQc.setPaySchId(pageVO.getWsPaySchId());
        prjPrdDtlQc.setSysCd(CurrentThreadContext.getCurrentSysCd());
        prjPrdDtlQc.setOrgCd(CurrentThreadContext.getCurrentOrgCd());
        List<PrjPrdDtlDTO> prjPrdDtlDTOList = projectApiService.selectPrjPrdDtlList(prjPrdDtlQc);
        if (CollectionUtils.isNotEmpty(prjPrdDtlDTOList)) {
            pageVO.setPrjPrdDtlId(prjPrdDtlDTOList.get(0).getId());
            pageVO.setPrjPrdId(prjPrdDtlDTOList.get(0).getPrjPrdId());
        }

        view.addObject("pay", pageVO);
    }

    public Long ifNull(Long amount) {
        return amount == null ? 0l : amount;
    }

}
